use std::io::Result;

trait Event {
    fn get_name(&self) -> String;
}

// remove the ugly (dyn Event)
trait Channel {
    type Event;

    fn peek(&self) -> Option<&Self::Event>;
    fn push(&mut self, e: Self::Event);
    fn pop(&mut self) -> Option<Self::Event>;
}


trait Source {
    type Channel;
    fn get_channel(&self) -> &Self::Channel;

    fn process(&self) -> Result<()>;
}









use std::fmt::Debug;

#[derive(Debug)]
struct MyEvent {
    name: String,
}
impl MyEvent {
    fn new(name: &str) -> Self{
        Self {
            name: name.to_owned()
        }
    }
}
impl Event for MyEvent {
    fn get_name(&self) -> String {
        String::clone(&self.name)
    }
}




#[derive(Debug)]
struct MyChannel<E>{
   e: Option<E>
}

impl<E> MyChannel<E>
where E: Event
{
    fn new() -> Self {
        Self {
            e: None
        }
    }
}

impl<E> Channel for MyChannel<E> 
where E: Event
{
    type Event = E;

    fn peek(&self) -> Option<&Self::Event>{
        self.e.as_ref()
    }
    fn pop(&mut self) -> Option<Self::Event>{
        self.e.take()
    }
    fn push(&mut self, e: E){
        self.e = Some(e);
    }
}





#[derive(Debug)]
struct MySource<'a, C> {
    c: &'a C,
    //fname: String,
    //lines: u64,
}

impl<'a, C> MySource<'a, C> 
where 
    C: Channel, 
{
    fn new<'b: 'a>(_fname: &str, _lines: u64, c: &'b C) -> Self {
        Self{
            c,
            //fname: fname.to_owned(),
            //lines,
        }
    }
}

impl<'a, C> Source for MySource<'a, C> 
where C: Channel
{
    type Channel = C;

    fn get_channel(&self) -> &Self::Channel {
        self.c
    }

    fn process(&self) -> Result<()>{
        //TODO:
        Ok(())
    }
}















#[derive(Debug)]
enum MyNewEvent {
    Hello,
    Login{ name: String},
    Request{ cmd: i32},
}
impl Event for MyNewEvent {
    fn get_name(&self) -> String {
        match self {
            MyNewEvent::Hello => "Hello".to_owned(),
            MyNewEvent::Login{name} =>  String::clone(name),
            MyNewEvent::Request{cmd,..} => cmd.to_string(),
        }
    }
}

use std::collections::vec_deque::VecDeque;

#[derive(Debug)]
struct FIFOChannel<E> {
    data: VecDeque<E>,
}

impl<E> FIFOChannel<E>
where E: Event
{
    fn new() -> Self {
        Self {
            data: VecDeque::new()
        }
    }
}

impl<E> Channel for FIFOChannel<E> 
where E: Event 
{
    type Event = E;

    fn peek(&self) -> Option<&Self::Event>{
        self.data.front()
    }
    fn pop(&mut self) -> Option<Self::Event>{
        self.data.pop_front()
    }
    fn push(&mut self, e: E) {
        self.data.push_back(e);
    }
}


#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn new_event_of_enum() {
        let e = MyNewEvent::Hello;
        println!("debug:{:?}", e);


        let mut c = FIFOChannel::new();
        c.push(e);
        println!("debug:{:?}, {:?}", c, c.peek());

        let e1 = MyNewEvent::Login{name:"chenglun".to_owned()};
        c.push(e1);
        println!("debug:{:?}, {:?}", c, c.peek());

        let e2 = MyNewEvent::Request{ cmd: 12};
        c.push(e2);
        println!("debug:{:?}, {:?}", c, c.peek());
        
    }

    #[test]
    fn first_impl_for_event(){
        let e = MyEvent::new("hello");
        assert_eq!(e.get_name(), "hello");

        println!("debug:{:?}", e);

        
        let mut c = MyChannel::new();
        c.push(e);
        println!("debug:{:?}, {:?}", c, c.peek());

        let v = c.pop();
        assert!(v.is_some());
        assert!(c.pop().is_none());
        c.push(v.unwrap());

        let s = MySource::new("main.rs", 10, &c);
        println!("debug:{:?}", s);
        println!("debug:{:?}", s.get_channel());

        let _ = s.process();
    }




}
